#ifndef __LINUX_DCACHE_H
#define __LINUX_DCACHE_H

#include <linux/list.h>
#include <linux/rculist.h>

#define IS_ROOT(x) ((x) == (x)->d_parent)

struct qstr {
	unsigned int hash;
	unsigned int len;
	const unsigned char *name;
};

#define init_name_hash()		0

static inline unsigned long partial_name_hash(unsigned long c, unsigned long prevhash)
{
	return (prevhash + (c << 4) + (c >> 4)) * 11;
}

static inline unsigned long end_name_hash(unsigned long hash)
{
	return (unsigned int) hash;
}

#define DNAME_INLINE_LEN_MIN 40 /* 128 bytes */

struct dentry {
	atomic_t d_count;
	unsigned int d_flags;		/* protected by d_lock */
	// spinlock_t d_lock;		/* per dentry lock */
	int d_mounted;
	struct inode *d_inode;		/* Where the name belongs to - NULL is
					 * negative */
	/*
	 * The next three fields are touched by __d_lookup.  Place them here
	 * so they all fit in a cache line.
	 */
	struct hlist_node d_hash;	/* lookup hash list */
	struct dentry *d_parent;	/* parent directory */
	struct qstr d_name;

	struct list_head d_lru;		/* LRU list */
	/*
	 * d_child and d_rcu can share memory
	 */
	union {
		struct list_head d_child;	/* child of parent list */
	 	// struct rcu_head d_rcu;
	} d_u;
	struct list_head d_subdirs;	/* our children */
	struct list_head d_alias;	/* inode alias list */
	unsigned long d_time;		/* used by d_revalidate */
	const struct dentry_operations *d_op;
	struct super_block *d_sb;	/* The root of the dentry tree */
	void *d_fsdata;			/* fs-specific data */

	unsigned char d_iname[DNAME_INLINE_LEN_MIN];	/* small names */
};

struct dentry_operations {
	int (*d_revalidate)(struct dentry *, struct nameidata *);
	int (*d_hash) (struct dentry *, struct qstr *);
	int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
	int (*d_delete)(struct dentry *);
	void (*d_release)(struct dentry *);
	void (*d_iput)(struct dentry *, struct inode *);
	char *(*d_dname)(struct dentry *, char *, int);
};

#define DCACHE_UNHASHED		0x0010	
#define	DCACHE_DISCONNECTED 0x0004

static inline void d_add(struct dentry *entry, struct inode *inode)
{
	d_instantiate(entry, inode);
	d_rehash(entry);
}

static inline int d_unhashed(struct dentry *dentry)
{
	return (dentry->d_flags & DCACHE_UNHASHED);
}

static inline int d_mountpoint(struct dentry *dentry)
{
	return dentry->d_mounted;
}

static inline struct dentry *dget(struct dentry *dentry)
{
	if (dentry) {
		// BUG_ON(!atomic_read(&dentry->d_count));
		// atomic_inc(&dentry->d_count);
	}
	return dentry;
}

static inline void __d_drop(struct dentry *dentry)
{
	if (!(dentry->d_flags & DCACHE_UNHASHED)) {
		dentry->d_flags |= DCACHE_UNHASHED;
		hlist_del_rcu(&dentry->d_hash);
	}
}

static inline int dname_external(struct dentry *dentry)
{
	return dentry->d_name.name != dentry->d_iname;
}

#endif
